package com.deer.wms.intercept.filter;

import com.deer.wms.intercept.entity.SecurityUser;
import com.deer.wms.intercept.entity.UserLogin;
import com.deer.wms.intercept.security.JwtUtil;
import com.deer.wms.project.root.core.result.CommonCode;
import com.deer.wms.project.root.core.result.ResultGenerator;
import com.deer.wms.project.root.util.RedisUtil;
import com.deer.wms.project.root.util.ResponseUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author : wei
 * @since : 2021-07-30 15:14:02
 **/
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
    private AuthenticationManager authenticationManager;
    private JwtUtil jwtUtil;
    private RedisUtil redisUtil;

    public TokenLoginFilter(AuthenticationManager authenticationManager, JwtUtil jwtUtil, RedisUtil redisUtil) {
        this.authenticationManager = authenticationManager;
        this.jwtUtil = jwtUtil;
        this.redisUtil = redisUtil;
        this.setPostOnly(false);
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login"));
    }


    /**
     * 一旦调用登录接口 /auth/login，立即执行该方法
     */
    @SneakyThrows
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        UserLogin user = new ObjectMapper().readValue(request.getInputStream(), UserLogin.class);
        //TODO: 验证码 https://mp.weixin.qq.com/s/aaop_dS9UIOgTtQd0hl_tw
//        String verify_code = (String) request.getSession().getAttribute("verify_code");
//        String code = loginData.get("code");
//        checkCode(response, code, verify_code);

        return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getAccount(),user.getPassword()));
    }

    /**
     * 认证成功，执行该方法
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        //认证成功，得到认证成功之后用户信息
        SecurityUser securityUser =(SecurityUser) authResult.getPrincipal();
        //根据用户名生成token
        String token = jwtUtil.generateToken(securityUser.getCurrentUserInfo().getAccount());

        try {
            //将用户名和用户权限列表放到redis
            //同时设置过期时间，24小时
            redisUtil.set(securityUser.getCurrentUserInfo().getAccount(), securityUser.getPermissionValueList(), 60L * 60 * 24);

            //返回token
            Map<String, String> map = new HashMap<>();
            map.put("token", token);
            ResponseUtil.out(response, ResultGenerator.genSuccessResult(map));
        }catch (Exception e) {
            ResponseUtil.out(response, ResultGenerator.genFailResult(CommonCode.REDIS_SERVER_ERROR));
        }

    }

    /**
     * 认证失败，立即执行该方法
     */
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        ResponseUtil.out(response, ResultGenerator.genFailResult(CommonCode.ACCOUNT_OR_PASSWORD_ERROR));
    }

    private void checkCode(HttpServletResponse resp, String code, String verify_code) {
        if (code == null || verify_code == null || "".equals(code) || !verify_code.toLowerCase().equals(code.toLowerCase())) {
            //验证码不正确
            throw new AuthenticationServiceException("验证码不正确");
        }
    }
}
